package com.lhl.jwt.handler;

import cn.hutool.json.JSONUtil;
import com.lhl.jwt.exception.JwtSignatureVerifyException;
import com.lhl.jwt.service.JwtUserDetailsService;
import com.lhl.jwt.token.JwtAuthenticationToken;
import com.lhl.jwt.utils.JwtConstant;
import com.lhl.jwt.utils.JwtUtils;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

/**
 * 验证token成功后判断是否需要刷新token
 * @author zhangyf
 * @date 2019年8月16日
 */
@Slf4j
public class JwtRefreshSuccessHandler implements AuthenticationSuccessHandler{

	private int tokenRefreshInterval; //如果不配置则默认不开启token刷新功能
	
	private JwtUserDetailsService jwtUserDetailsService;
	
	private UserCache userCache = new NullUserCache();
	
	public JwtRefreshSuccessHandler(JwtUserDetailsService jwtUserService) {
		this.jwtUserDetailsService = jwtUserService;
	}

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		SignedJWT jwt = ((JwtAuthenticationToken)authentication).getToken();
		log.debug("jwt=={}", JSONUtil.toJsonStr(jwt));
		try{
			boolean shouldRefresh = shouldTokenRefresh(jwt.getJWTClaimsSet().getIssueTime());
			//根据用户配置判断token是否过期
			if(shouldRefresh) {
				//刷新token
				//这里根据配置会刷新 Cache、DB中的token
				UserDetails user = (UserDetails)authentication.getPrincipal();

				userCache.putUserInCache(user);

//				String salt = jwtUserDetailsService.getSalt(user.getUsername());
//				if (StringUtils.isBlank(salt)) {
//					salt = JwtUtils.TOKEN_SECRET;
//				}
				String newToken = generToken(user, user.getUsername());
//				jwtUserDetailsService.insertSalt(newToken, user);

				response.setHeader(JwtConstant.AUTHORIZATION_HEADER, JwtConstant.AUTHORIZATION_START_STRING + newToken);
				response.setHeader(JwtConstant.ACCESS_CONTROL_EXPOSE_HEADER, JwtConstant.AUTHORIZATION_HEADER);

				log.info("token refresh, new token : " + newToken);
			}
		}catch (ParseException pe){
			throw new JwtSignatureVerifyException("生成TOKEN异常");
		}

	}
	
	protected boolean shouldTokenRefresh(Date issueAt){
		if (tokenRefreshInterval == 0 ) return false;
		
        LocalDateTime issueTime = LocalDateTime.ofInstant(issueAt.toInstant(), ZoneId.systemDefault());
        return LocalDateTime.now().minusSeconds(tokenRefreshInterval).isAfter(issueTime);
    }
	
	private String generToken(UserDetails user, String salt) {
		try{
			return JwtUtils.createToken(user.getUsername(), user.getAuthorities(), salt);
		}catch (JOSEException e){
			throw new JwtSignatureVerifyException("生成TOKEN异常");
		}
	}

	public void setUserCache(UserCache userCache) {
		this.userCache = userCache;
	}

	public void setTokenRefreshInterval(int tokenRefreshInterval) {
		this.tokenRefreshInterval = tokenRefreshInterval;
	}
	
}
